Beispiel #1
0
void   CZLibReadBuffer::seek2CurBlock()
{
	int curBlockIndex;
	for(int i = 0 ; i  < m_FileHeader.m_nBlock  ; i++ )
	{
		if( m_DataNowPos < m_FileHeader.m_pEntris[i].m_dataBegPos)
		{
			curBlockIndex = i - 1;
			m_curBlockReadPos = m_DataNowPos - m_FileHeader.m_pEntris[i - 1].m_dataBegPos;
			if(m_curBlockIndex != curBlockIndex)
			{
				m_FileHeader.m_pEntris[m_curBlockIndex].Release();
				cacheBlock(curBlockIndex);
			}
			m_curBlockIndex=curBlockIndex;
			return ;
		}
	}

	curBlockIndex   = m_FileHeader.m_nBlock - 1 ;
	m_curBlockReadPos = m_DataNowPos - m_FileHeader.m_pEntris[m_FileHeader.m_nBlock - 1].m_dataBegPos;
	if(m_curBlockIndex != curBlockIndex)
	{
		m_FileHeader.m_pEntris[m_curBlockIndex].Release();
		cacheBlock(curBlockIndex);
	}
	m_curBlockIndex=curBlockIndex;
}
Beispiel #2
0
int    CZLibReadBuffer::read(_xcd_int8* buf, int byte_read)
{
	int byte_need_read = byte_read;
	if( size_t(m_DataNowPos + byte_read) > size_t(m_DataLen) )
	{
		byte_need_read =  m_DataLen - m_DataNowPos ;
	}
	if(byte_need_read == 0)
		return 0;

	CCDCompressedDataPackBuffer& readBlock = m_FileHeader.m_pEntris[m_curBlockIndex];

	int byteInThisBlock = readBlock.m_Info.m_DataSize - m_curBlockReadPos;

	if(readBlock.buffer == NULL) 
		cacheBlock(m_curBlockIndex);

	if(byteInThisBlock >= byte_need_read)
	{
		memcpy(buf,readBlock.buffer + m_curBlockReadPos  , byte_need_read) ;
		m_curBlockReadPos += byte_need_read;
		m_DataNowPos      += byte_need_read;  
		return byte_need_read;        
	}
	else
	{
		memcpy(buf,readBlock.buffer + m_curBlockReadPos  , byteInThisBlock) ;
		m_DataNowPos      += byteInThisBlock;
		m_curBlockIndex ++;
		readBlock.Release();
		cacheBlock(m_curBlockIndex);
		m_curBlockReadPos = 0;
		return byteInThisBlock + read(buf + byteInThisBlock , byte_need_read - byteInThisBlock);
	}
}
 void initComplexSyncCache(uint32_t s_idx, uint32_t e_idx)
 {
   sbdi_block_t blk;
   cacheBlock(&blk, s_idx, SBDI_BC_BT_MNGT);
   for (uint32_t i = s_idx + 1; i < e_idx; ++i) {
     cacheBlock(&blk, i, SBDI_BC_BT_DATA);
   }
 }
 void testComplexSync()
 {
   sbdi_block_t blk;
   initComplexSyncCache(0x00, (SBDI_CACHE_MAX_SIZE / 2));
   initComplexSyncCache(0x80, 0x80 + (SBDI_CACHE_MAX_SIZE / 2));
   complexSyncDirtyBlocks(0x00, (SBDI_CACHE_MAX_SIZE / 2));
   complexSyncDirtyBlocks(0x80, 0x80 + (SBDI_CACHE_MAX_SIZE / 2));
   cacheBlock(&blk, 0x200, SBDI_BC_BT_DATA);
   exp_sync.insert(exp_sync.begin(), 0x02);
   cacheBlock(&blk, 0x201, SBDI_BC_BT_DATA);
   CPPUNIT_ASSERT(exp_sync.size() == 0);
   exp_sync.clear();
 }
int CGitLogList::CherryPickFrom(CString from, CString to)
{
	CLogDataVector logs(&m_LogCache);
	if(logs.ParserFromLog(NULL,-1,0,&from,&to))
		return -1;

	if(logs.size() == 0)
		return 0;

	CSysProgressDlg progress;
	if (progress.IsValid())
	{
		progress.SetTitle(_T("Cherry Pick"));
		progress.SetAnimation(IDR_MOVEANI);
		progress.SetTime(true);
		progress.ShowModeless(this);
	}

	CBlockCacheForPath cacheBlock(g_Git.m_CurrentDir);

	for(int i=logs.size()-1;i>=0;i--)
	{
		if (progress.IsValid())
		{
			progress.FormatPathLine(1, _T("Pick up %s"), logs.GetGitRevAt(i).m_CommitHash.ToString());
			progress.FormatPathLine(2, _T("%s"), logs.GetGitRevAt(i).GetSubject());
			progress.SetProgress(logs.size()-i, logs.size());
		}
		if ((progress.IsValid())&&(progress.HasUserCancelled()))
		{
			//CMessageBox::Show(hwndExplorer, IDS_SVN_USERCANCELLED, IDS_APPNAME, MB_ICONINFORMATION);
			throw std::exception(CUnicodeUtils::GetUTF8(CString(_T("User canceled\r\n\r\n"))));
			return -1;
		}
		CString cmd,out;
		cmd.Format(_T("git.exe cherry-pick %s"),logs.GetGitRevAt(i).m_CommitHash.ToString());
		out.Empty();
		if(g_Git.Run(cmd,&out,CP_UTF8))
		{
			throw std::exception(CUnicodeUtils::GetUTF8(CString(_T("Cherry Pick Failure\r\n\r\n"))+out));
			return -1;
		}
	}

	return 0;
}
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
  i64 offset;       /* The current offset from the start of the file */
  i64 end;          /* The byte just past the last byte written */
  int blk;            /* Block number the write starts on */
  int i;
  const u8 *zCsr;
  int rc = SQLITE_OK;
  OsTestFile *pFile = *id;

  offset = osTell(pFile);
  end = offset+amt;
  blk = (offset/BLOCKSIZE);

  zCsr = (u8 *)pBuf;
  for(i=blk; i*BLOCKSIZE<end; i++){
    u8 *pBlk;
    int off = 0;
    int len = 0;

    /* Make sure the block is in the cache */
    rc = cacheBlock(pFile, i);
    if( rc!=SQLITE_OK ) return rc;

    /* Write into the cache */
    pBlk = pFile->apBlk[i];
    assert( pBlk );

    if( BLOCK_OFFSET(i) < offset ){
      off = offset-BLOCK_OFFSET(i);
    }
    len = BLOCKSIZE - off;
    if( BLOCK_OFFSET(i+1) > end ){
      len = len - (BLOCK_OFFSET(i+1)-end);
    }
    memcpy(&pBlk[off], zCsr, len);
    zCsr += len;
  }
  if( pFile->nMaxWrite<end ){
    pFile->nMaxWrite = end;
  }
  assert( zCsr==&((u8 *)pBuf)[amt] );

  rc = sqlite3RealSeek(&pFile->fd, end);
  return rc;
}
int CGitLogList::CherryPickFrom(CString from, CString to)
{
	CLogDataVector logs(&m_LogCache);
	CString range;
	range.Format(_T("%s..%s"), (LPCTSTR)from, (LPCTSTR)to);
	if (logs.ParserFromLog(nullptr, 0, 0, &range))
		return -1;

	if (logs.empty())
		return 0;

	CSysProgressDlg progress;
	progress.SetTitle(CString(MAKEINTRESOURCE(IDS_PROGS_TITLE_CHERRYPICK)));
	progress.SetAnimation(IDR_MOVEANI);
	progress.SetTime(true);
	progress.ShowModeless(this);

	CBlockCacheForPath cacheBlock(g_Git.m_CurrentDir);

	for (int i = (int)logs.size() - 1; i >= 0; i--)
	{
		if (progress.IsVisible())
		{
			progress.FormatNonPathLine(1, IDS_PROC_PICK, logs.GetGitRevAt(i).m_CommitHash.ToString());
			progress.FormatNonPathLine(2, _T("%s"), (LPCTSTR)logs.GetGitRevAt(i).GetSubject());
			progress.SetProgress64(logs.size() - i, logs.size());
		}
		if (progress.HasUserCancelled())
		{
			throw std::exception(CUnicodeUtils::GetUTF8(CString(MAKEINTRESOURCE(IDS_USERCANCELLED))));
		}
		CString cmd,out;
		cmd.Format(_T("git.exe cherry-pick %s"), (LPCTSTR)logs.GetGitRevAt(i).m_CommitHash.ToString());
		out.Empty();
		if(g_Git.Run(cmd,&out,CP_UTF8))
		{
			throw std::exception(CUnicodeUtils::GetUTF8(CString(MAKEINTRESOURCE(IDS_PROC_CHERRYPICKFAILED)) + _T(":\r\n\r\n") + out));
		}
	}

	return 0;
}
Beispiel #8
0
int CRebaseDlg::RebaseThread()
{
	CBlockCacheForPath cacheBlock(g_Git.m_CurrentDir);

	int ret=0;
	while(1)
	{
		if( m_RebaseStage == REBASE_START )
		{
			if( this->StartRebase() )
			{
				InterlockedExchange(&m_bThreadRunning, FALSE);
				ret = -1;
				this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
				break;
			}
			m_RebaseStage = REBASE_CONTINUE;

		}
		else if( m_RebaseStage == REBASE_CONTINUE )
		{
			this->GoNext();
			UpdateCurrentStatus();
			if(IsEnd())
			{
				ret = 0;
				m_RebaseStage = REBASE_FINISH;

			}
			else
			{
				ret = DoRebase();

				if( ret )
				{
					break;
				}
			}

		}
		else if( m_RebaseStage == REBASE_FINISH )
		{
			FinishRebase();
			m_RebaseStage = REBASE_DONE;
			if (m_pTaskbarList)
				m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
			break;

		}
		else
		{
			break;
		}
		this->PostMessage(MSG_REBASE_UPDATE_UI);
		//this->UpdateCurrentStatus();
	}

	InterlockedExchange(&m_bThreadRunning, FALSE);
	this->PostMessage(MSG_REBASE_UPDATE_UI);
	return ret;
}
bool DiffCommand::Execute()
{
	bool bRet = false;
	CString path2 = CPathUtils::GetLongPathname(parser.GetVal(_T("path2")));
	bool bAlternativeTool = !!parser.HasKey(_T("alternative"));
//	bool bBlame = !!parser.HasKey(_T("blame"));
	if (path2.IsEmpty())
	{
		if (this->orgCmdLinePath.IsDirectory())
		{
			CChangedDlg dlg;
			dlg.m_pathList = CTGitPathList(cmdLinePath);
			dlg.DoModal();
			bRet = true;
		}
		else
		{
			if (cmdLinePath.IsEmpty())
				return false;
			CGitDiff diff;
			//diff.SetAlternativeTool(bAlternativeTool);
			if ( parser.HasKey(_T("startrev")) && parser.HasKey(_T("endrev")) )
			{
				if (parser.HasKey(_T("unified")))
					bRet = !!CAppUtils::StartShowUnifiedDiff(nullptr, cmdLinePath, git_revnum_t(parser.GetVal(_T("endrev"))), cmdLinePath, git_revnum_t(parser.GetVal(_T("startrev"))), bAlternativeTool);
				else
					bRet = !!diff.Diff(&cmdLinePath, &cmdLinePath, git_revnum_t(parser.GetVal(_T("startrev"))), git_revnum_t(parser.GetVal(_T("endrev"))), false, parser.HasKey(_T("unified")) == TRUE, parser.GetLongVal(_T("line")), bAlternativeTool);
			}
			else
			{
				// check if it is a newly added (but uncommitted) file
				git_wc_status_kind status = git_wc_status_none;
				CString topDir;
				if (orgCmdLinePath.HasAdminDir(&topDir))
				{
					CBlockCacheForPath cacheBlock(topDir);
					CAutoIndex index;
					CString adminDir;
					GitAdminDir::GetAdminDirPath(topDir, adminDir);
					if (!git_index_open(index.GetPointer(), CUnicodeUtils::GetUTF8(adminDir + _T("index"))))
						g_Git.Run(_T("git.exe update-index -- \"") + cmdLinePath.GetGitPathString() + _T("\""), nullptr); // make sure we get the right status
					GitStatus::GetFileStatus(topDir, cmdLinePath.GetWinPathString(), &status, true);
					if (index)
						git_index_write(index);
				}
				if (status == git_wc_status_added)
				{
					if (!g_Git.IsInitRepos())
					{
						// this might be a rename, try to find original name
						BYTE_VECTOR cmdout;
						g_Git.Run(_T("git.exe diff-index --raw HEAD -M -C -z --"), &cmdout);
						CTGitPathList changedFiles;
						changedFiles.ParserFromLog(cmdout);
						for (int i = 0; i < changedFiles.GetCount(); ++i)
						{
							if (changedFiles[i].GetGitPathString() == cmdLinePath.GetGitPathString())
							{
								if (!changedFiles[i].GetGitOldPathString().IsEmpty())
								{
									CTGitPath oldPath(changedFiles[i].GetGitOldPathString());
									if (parser.HasKey(_T("unified")))
										return !!CAppUtils::StartShowUnifiedDiff(nullptr, cmdLinePath, git_revnum_t(_T("HEAD")), cmdLinePath, git_revnum_t(GIT_REV_ZERO), bAlternativeTool);
									return !!diff.Diff(&cmdLinePath, &oldPath, git_revnum_t(GIT_REV_ZERO), git_revnum_t(_T("HEAD")), false, parser.HasKey(_T("unified")) == TRUE, parser.GetLongVal(_T("line")), bAlternativeTool);
								}
								break;
							}
						}
					}
					cmdLinePath.m_Action = cmdLinePath.LOGACTIONS_ADDED;
				}

				if (parser.HasKey(_T("unified")))
					bRet = !!CAppUtils::StartShowUnifiedDiff(nullptr, cmdLinePath, git_revnum_t(_T("HEAD")), cmdLinePath, git_revnum_t(GIT_REV_ZERO), bAlternativeTool);
				else
					bRet = !!diff.Diff(&cmdLinePath, &cmdLinePath, git_revnum_t(GIT_REV_ZERO), git_revnum_t(_T("HEAD")), false, parser.HasKey(_T("unified")) == TRUE, parser.GetLongVal(_T("line")), bAlternativeTool);
			}
		}
	}
	else
	{
		CGitDiff diff;
		if ( parser.HasKey(_T("startrev")) && parser.HasKey(_T("endrev")) && path2.Left(g_Git.m_CurrentDir.GetLength() + 1) == g_Git.m_CurrentDir + _T("\\"))
		{
			CTGitPath tgitPath2 = path2.Mid(g_Git.m_CurrentDir.GetLength() + 1);
			bRet = !!diff.Diff(&tgitPath2, &cmdLinePath, git_revnum_t(parser.GetVal(_T("startrev"))), git_revnum_t(parser.GetVal(_T("endrev"))), false, parser.HasKey(_T("unified")) == TRUE, parser.GetLongVal(_T("line")), bAlternativeTool);
		}
		else
		{
			bRet = CAppUtils::StartExtDiff(
				path2, orgCmdLinePath.GetWinPathString(), CString(), CString(),
				CString(), CString(), git_revnum_t(GIT_REV_ZERO), git_revnum_t(GIT_REV_ZERO),
				CAppUtils::DiffFlags().AlternativeTool(bAlternativeTool), parser.GetLongVal(_T("line")));
		}
	}

	return bRet;
}
int CGitLogList::RevertSelectedCommits(int parent)
{
	CSysProgressDlg progress;
	int ret = -1;

#if 0
	if(!g_Git.CheckCleanWorkTree())
	{
		CMessageBox::Show(NULL, IDS_PROC_NOCLEAN, IDS_APPNAME, MB_OK);

	}
#endif

	if (this->GetSelectedCount() > 1)
	{
		progress.SetTitle(CString(MAKEINTRESOURCE(IDS_PROGS_TITLE_REVERTCOMMIT)));
		progress.SetAnimation(IDR_MOVEANI);
		progress.SetTime(true);
		progress.ShowModeless(this);
	}

	CBlockCacheForPath cacheBlock(g_Git.m_CurrentDir);

	POSITION pos = GetFirstSelectedItemPosition();
	int i=0;
	while(pos)
	{
		int index = GetNextSelectedItem(pos);
		GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(index));

		if (progress.IsVisible())
		{
			progress.FormatNonPathLine(1, IDS_PROC_REVERTCOMMIT, r1->m_CommitHash.ToString());
			progress.FormatNonPathLine(2, _T("%s"), (LPCTSTR)r1->GetSubject());
			progress.SetProgress(i, this->GetSelectedCount());
		}
		++i;

		if(r1->m_CommitHash.IsEmpty())
			continue;

		if (g_Git.GitRevert(parent, r1->m_CommitHash))
		{
			CString str;
			str.LoadString(IDS_SVNACTION_FAILEDREVERT);
			str = g_Git.GetGitLastErr(str, CGit::GIT_CMD_REVERT);
			if( GetSelectedCount() == 1)
				CMessageBox::Show(NULL, str, _T("TortoiseGit"), MB_OK | MB_ICONERROR);
			else
			{
				if(CMessageBox::Show(NULL, str, _T("TortoiseGit"),2 , IDI_ERROR, CString(MAKEINTRESOURCE(IDS_SKIPBUTTON)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON))) == 2)
				{
					return ret;
				}
			}
		}
		else
		{
			ret =0;
		}

		if (progress.HasUserCancelled())
			break;
	}
	return ret;
}
Beispiel #11
0
//static function, Share with SyncDialog
UINT CProgressDlg::RunCmdList(CWnd *pWnd,std::vector<CString> &cmdlist,bool bShowCommand,CString *pfilename,bool *bAbort,CGitByteArray *pdata, CGit *git)
{
	UINT ret=0;

	PROCESS_INFORMATION pi;
	HANDLE hRead = 0;

	memset(&pi,0,sizeof(PROCESS_INFORMATION));

	CBlockCacheForPath cacheBlock(git->m_CurrentDir);

	EnsurePostMessage(pWnd, MSG_PROGRESSDLG_UPDATE_UI, MSG_PROGRESSDLG_START, 0);

	if(pdata)
		pdata->clear();

	for (size_t i = 0; i < cmdlist.size(); ++i)
	{
		if(cmdlist[i].IsEmpty())
			continue;

		if (bShowCommand)
		{
			CStringA str = CUnicodeUtils::GetMulti(cmdlist[i].Trim() + _T("\r\n\r\n"), CP_UTF8);
			for (int j = 0; j < str.GetLength(); ++j)
			{
				if(pdata)
				{
					pdata->m_critSec.Lock();
					pdata->push_back(str[j]);
					pdata->m_critSec.Unlock();
				}
				else
					pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,str[j]);
			}
			if(pdata)
				pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);
		}

		git->RunAsync(cmdlist[i].Trim(),&pi, &hRead, NULL, pfilename);

		DWORD readnumber;
		char lastByte = '\0';
		char byte;
		CString output;
		while(ReadFile(hRead,&byte,1,&readnumber,NULL))
		{
			if(pdata)
			{
				if(byte == 0)
					byte = '\n';

				pdata->m_critSec.Lock();
				if (byte == '\n' && lastByte != '\r')
					pdata->push_back('\r');
				pdata->push_back( byte);
				lastByte = byte;
				pdata->m_critSec.Unlock();

				if(byte == '\r' || byte == '\n')
					pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);
			}
			else
				pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,byte);
		}
		if (pdata)
		{
			pdata->m_critSec.Lock();
			bool post = !pdata->empty();
			pdata->m_critSec.Unlock();
			if (post)
				EnsurePostMessage(pWnd, MSG_PROGRESSDLG_UPDATE_UI, MSG_PROGRESSDLG_RUN, 0);
		}

		CloseHandle(pi.hThread);

		CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": waiting for process to finish (%s), aborted: %d\n"), cmdlist[i], *bAbort);

		WaitForSingleObject(pi.hProcess, INFINITE);

		DWORD status=0;
		if(!GetExitCodeProcess(pi.hProcess,&status) || *bAbort)
		{
			CloseHandle(pi.hProcess);

			CloseHandle(hRead);

			CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": process %s finished, status code could not be fetched, (error %d; %s), aborted: %d\n"), cmdlist[i], GetLastError(), (CString)CFormatMessageWrapper(), *bAbort);

			EnsurePostMessage(pWnd, MSG_PROGRESSDLG_UPDATE_UI, MSG_PROGRESSDLG_FAILED, status);
			return TGIT_GIT_ERROR_GET_EXIT_CODE;
		}
		CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": process %s finished with code %d\n"), cmdlist[i], status);
		ret |= status;
	}

	CloseHandle(pi.hProcess);

	CloseHandle(hRead);

	EnsurePostMessage(pWnd, MSG_PROGRESSDLG_UPDATE_UI, MSG_PROGRESSDLG_END, ret);

	return ret;
}
void MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool urgent)
{
	MutexAutoLock lock(m_mutex);

	cleanupCache();

	/*
		Cache the block data (force-update the center block, don't update the
		neighbors but get them if they aren't already cached)
	*/
	std::vector<CachedMapBlockData*> cached_blocks;
	size_t cache_hit_counter = 0;
	cached_blocks.reserve(3*3*3);
	v3s16 dp;
	for (dp.X = -1; dp.X <= 1; dp.X++)
	for (dp.Y = -1; dp.Y <= 1; dp.Y++)
	for (dp.Z = -1; dp.Z <= 1; dp.Z++) {
		v3s16 p1 = p + dp;
		CachedMapBlockData *cached_block;
		if (dp == v3s16(0, 0, 0))
			cached_block = cacheBlock(map, p1, FORCE_UPDATE);
		else
			cached_block = cacheBlock(map, p1, SKIP_UPDATE_IF_ALREADY_CACHED,
					&cache_hit_counter);
		cached_blocks.push_back(cached_block);
	}
	g_profiler->avg("MeshUpdateQueue MapBlock cache hit %",
			100.0f * cache_hit_counter / cached_blocks.size());

	/*
		Mark the block as urgent if requested
	*/
	if (urgent)
		m_urgents.insert(p);

	/*
		Find if block is already in queue.
		If it is, update the data and quit.
	*/
	for (QueuedMeshUpdate *q : m_queue) {
		if (q->p == p) {
			// NOTE: We are not adding a new position to the queue, thus
			//       refcount_from_queue stays the same.
			if(ack_block_to_server)
				q->ack_block_to_server = true;
			q->crack_level = m_client->getCrackLevel();
			q->crack_pos = m_client->getCrackPos();
			return;
		}
	}

	/*
		Add the block
	*/
	QueuedMeshUpdate *q = new QueuedMeshUpdate;
	q->p = p;
	q->ack_block_to_server = ack_block_to_server;
	q->crack_level = m_client->getCrackLevel();
	q->crack_pos = m_client->getCrackPos();
	m_queue.push_back(q);

	// This queue entry is a new reference to the cached blocks
	for (CachedMapBlockData *cached_block : cached_blocks) {
		cached_block->refcount_from_queue++;
	}
}
Beispiel #13
0
//static function, Share with SyncDialog
UINT CProgressDlg::RunCmdList(CWnd *pWnd,std::vector<CString> &cmdlist,bool bShowCommand,CString *pfilename,bool *bAbort,CGitByteArray *pdata)
{
	UINT ret=0;

	PROCESS_INFORMATION pi;
	HANDLE hRead = 0;

	memset(&pi,0,sizeof(PROCESS_INFORMATION));

	CBlockCacheForPath cacheBlock(g_Git.m_CurrentDir);

	pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_START,0);

	if(pdata)
		pdata->clear();

	for(int i=0;i<cmdlist.size();i++)
	{
		if(cmdlist[i].IsEmpty())
			continue;

		if (bShowCommand)
		{
			CStringA str = CUnicodeUtils::GetMulti(cmdlist[i].Trim() + _T("\n\n"), CP_UTF8);
			for(int j=0;j<str.GetLength();j++)
			{
				if(pdata)
				{
					pdata->m_critSec.Lock();
					pdata->push_back(str[j]);
					pdata->m_critSec.Unlock();
				}
				else
					pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,str[j]);
			}
			if(pdata)
				pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);
		}

		g_Git.RunAsync(cmdlist[i].Trim(),&pi, &hRead, NULL, pfilename);

		DWORD readnumber;
		char byte;
		CString output;
		while(ReadFile(hRead,&byte,1,&readnumber,NULL))
		{
			if(pdata)
			{
				if(byte == 0)
					byte = '\n';

				pdata->m_critSec.Lock();
				pdata->push_back( byte);
				pdata->m_critSec.Unlock();

				if(byte == '\r' || byte == '\n')
					pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);
			}
			else
				pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,byte);
		}

		CloseHandle(pi.hThread);

		WaitForSingleObject(pi.hProcess, INFINITE);

		DWORD status=0;
		if(!GetExitCodeProcess(pi.hProcess,&status) || *bAbort)
		{
			CloseHandle(pi.hProcess);

			CloseHandle(hRead);

			pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI, MSG_PROGRESSDLG_FAILED, status);
			return TGIT_GIT_ERROR_GET_EXIT_CODE;
		}
		ret |= status;
	}

	CloseHandle(pi.hProcess);

	CloseHandle(hRead);

	pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI, MSG_PROGRESSDLG_END, ret);

	return ret;

}
int CGitLogList::RevertSelectedCommits()
{
	CSysProgressDlg progress;
	int ret = -1;

#if 0
	if(!g_Git.CheckCleanWorkTree())
	{
		CMessageBox::Show(NULL,_T("Revert requires a clean working tree"),_T("TortoiseGit"),MB_OK);

	}
#endif

	if (progress.IsValid() && (this->GetSelectedCount() > 1) )
	{
		progress.SetTitle(_T("Revert Commit"));
		progress.SetAnimation(IDR_MOVEANI);
		progress.SetTime(true);
		progress.ShowModeless(this);
	}

	CBlockCacheForPath cacheBlock(g_Git.m_CurrentDir);

	POSITION pos = GetFirstSelectedItemPosition();
	int i=0;
	while(pos)
	{
		int index = GetNextSelectedItem(pos);
		GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(index));

		if (progress.IsValid() && (this->GetSelectedCount() > 1) )
		{
			progress.FormatPathLine(1, _T("Revert %s"), r1->m_CommitHash.ToString());
			progress.FormatPathLine(2, _T("%s"),        r1->GetSubject());
			progress.SetProgress(i,         this->GetSelectedCount());
		}
		i++;

		if(r1->m_CommitHash.IsEmpty())
			continue;

		CString cmd, output;
		cmd.Format(_T("git.exe revert --no-edit --no-commit %s"), r1->m_CommitHash.ToString());
		if(g_Git.Run(cmd, &output, CP_ACP))
		{
			CString str;
			str=_T("Revert fail\n");
			str+= cmd;
			str+= _T("\n")+output;
			if( GetSelectedCount() == 1)
				CMessageBox::Show(NULL,str, _T("TortoiseGit"),MB_OK|MB_ICONERROR);
			else
			{
				if(CMessageBox::Show(NULL, str, _T("TortoiseGit"),2 , IDI_ERROR, _T("&Skip"), _T("&Abort")) == 2)
				{
					return ret;
				}
			}
		}
		else
		{
			ret =0;
		}

		if ((progress.IsValid())&&(progress.HasUserCancelled()))
			break;
	}
	return ret;
}