@@ -1772,6 +1772,142 @@ def ensure_git_credential_cache_daemon(
1772
1772
elif self ._GIT_CREDENTIAL_CACHE_DAEMON_PROCESS .poll ():
1773
1773
self .ensure_git_credential_cache_daemon (socket , debug , True , cwd , env )
1774
1774
1775
+ async def stash (self , path : str , stashMsg : str = "" ) -> dict :
1776
+ """
1777
+ Stash changes in a dirty working directory away
1778
+ path: str Git path repository
1779
+ stashMsg (optional): str
1780
+ A message that describes the stash entry
1781
+ """
1782
+ cmd = ["git" , "stash" ]
1783
+
1784
+ if len (stashMsg ) > 0 :
1785
+ cmd .extend (["save" , "-m" , stashMsg ])
1786
+
1787
+ env = os .environ .copy ()
1788
+ # if the git command is run in a non-interactive terminal, it will not prompt for user input
1789
+ env ["GIT_TERMINAL_PROMPT" ] = "0"
1790
+
1791
+ code , output , error = await execute (cmd , cwd = path , env = env )
1792
+
1793
+ # code 0: no changes to stash
1794
+ if code != 0 :
1795
+ return {"code" : code , "command" : " " .join (cmd ), "message" : error }
1796
+ return {"code" : code , "message" : output , "command" : " " .join (cmd )}
1797
+
1798
+ async def stash_list (self , path : str ) -> dict :
1799
+ """
1800
+ Execute git stash list command
1801
+ """
1802
+ cmd = ["git" , "stash" , "list" ]
1803
+
1804
+ env = os .environ .copy ()
1805
+ env ["GIT_TERMINAL_PROMPT" ] = "0"
1806
+
1807
+ code , output , error = await execute (cmd , cwd = path , env = env )
1808
+
1809
+ if code != 0 :
1810
+ return {"code" : code , "command" : " " .join (cmd ), "message" : error }
1811
+
1812
+ return {"code" : code , "message" : output , "command" : " " .join (cmd )}
1813
+
1814
+ async def stash_show (self , path : str , index : int ) -> dict :
1815
+ """
1816
+ Execute git stash show command
1817
+ """
1818
+ # stash_index = "stash@{" + str(index) + "}"
1819
+ stash_index = f"stash@{{{ index !s} }}"
1820
+
1821
+ cmd = ["git" , "stash" , "show" , "-p" , stash_index , "--name-only" ]
1822
+
1823
+ env = os .environ .copy ()
1824
+ env ["GIT_TERMINAL_PROMPT" ] = "0"
1825
+
1826
+ code , output , error = await execute (cmd , cwd = path , env = env )
1827
+
1828
+ if code != 0 :
1829
+ return {"code" : code , "command" : " " .join (cmd ), "message" : error }
1830
+
1831
+ return {"code" : code , "message" : output , "command" : " " .join (cmd )}
1832
+
1833
+ async def pop_stash (self , path : str , stash_index : Optional [int ] = None ) -> dict :
1834
+ """
1835
+ Execute git stash pop for a certain index of the stash list. If no index is provided, it will
1836
+
1837
+ path: str
1838
+ Git path repository
1839
+ stash_index: number
1840
+ Index of the stash list is first applied to the current branch, then removed from the stash.
1841
+ If the index is not provided, the most recent stash (index=0) will be removed from the stash.
1842
+ """
1843
+ cmd = ["git" , "stash" , "pop" ]
1844
+
1845
+ if stash_index :
1846
+ cmd .append (str (stash_index ))
1847
+
1848
+ env = os .environ .copy ()
1849
+ env ["GIT_TERMINAL_PROMPT" ] = "0"
1850
+
1851
+ code , output , error = await execute (cmd , cwd = path , env = env )
1852
+
1853
+ if code != 0 :
1854
+ return {"code" : code , "command" : " " .join (cmd ), "message" : error }
1855
+
1856
+ return {"code" : code , "message" : output , "command" : " " .join (cmd )}
1857
+
1858
+ async def drop_stash (self , path , stash_index : Optional [int ] = None ) -> dict :
1859
+ """
1860
+ Execute git stash drop to delete a single stash entry.
1861
+ If not stash_index is provided, delete the entire stash.
1862
+
1863
+ path: Git path repository
1864
+ stash_index: number or None
1865
+ Index of the stash list to remove from the stash.
1866
+ If None, the entire stash is removed.
1867
+ """
1868
+ cmd = ["git" , "stash" ]
1869
+ if stash_index is None :
1870
+ cmd .append ("clear" )
1871
+ else :
1872
+ cmd .extend (["drop" , str (stash_index )])
1873
+
1874
+ env = os .environ .copy ()
1875
+ env ["GIT_TERMINAL_PROMPT" ] = "0"
1876
+
1877
+ code , output , error = await execute (cmd , cwd = path , env = env )
1878
+
1879
+ if code != 0 :
1880
+ return {"code" : code , "command" : " " .join (cmd ), "message" : error }
1881
+
1882
+ return {"code" : code , "message" : output , "command" : " " .join (cmd )}
1883
+
1884
+ async def apply_stash (self , path : str , stash_index : Optional [int ] = None ) -> dict :
1885
+ """
1886
+ Execute git stash apply to apply a single stash entry to the repository.
1887
+ If not stash_index is provided, apply the latest stash.
1888
+
1889
+ path: str
1890
+ Git path repository
1891
+ stash_index: number
1892
+ Index of the stash list is applied to the repository.
1893
+ """
1894
+ # Clear
1895
+ cmd = ["git" , "stash" , "apply" ]
1896
+
1897
+ if stash_index is not None :
1898
+ cmd .append ("stash@{" + str (stash_index ) + "}" )
1899
+
1900
+ env = os .environ .copy ()
1901
+ env ["GIT_TERMINAL_PROMPT" ] = "0"
1902
+
1903
+ code , output , error = await execute (cmd , cwd = path , env = env )
1904
+
1905
+ # error:
1906
+ if code != 0 :
1907
+ return {"code" : code , "command" : " " .join (cmd ), "message" : error }
1908
+
1909
+ return {"code" : code , "message" : output , "command" : " " .join (cmd )}
1910
+
1775
1911
@property
1776
1912
def excluded_paths (self ) -> List [str ]:
1777
1913
"""Wildcard-style path patterns that do not support git commands.
0 commit comments